// const chalk = require('chalk')
import chalk from 'chalk'
// const pkg = require('../package.json')
import pkg from '../package.json' assert { type: "json" }


// ↓三种方式都可以
// const {Command} = require('commander');
// const program = new Command('create-react-app');
//
// const commander = require('commander');
// import commander from 'commander';
// const program = new commander.Command()
// ↑ 新版貌似不支持这种默认导出引入的方式了， 直接↓
import {program, Command} from 'commander';
//
//
// 单例的方式
// const program = require('commander').program;


//region 1. -V/--version 和 -h/--help
// program
//   .version('1.0.0') //设置版本号
//   .parse(process.argv)

// 相比yargs ,默认就支持 -V 和 -h
//
// PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js --version
// 1.0.0
// PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js -h
// Usage: 02.commander [options]
//
// Options:
//   -V, --version  output the version number
// -h, --help     display help for command
//   PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js -V
// 1.0.0

//endregion



//region 2. usage、name、option , `<>`是必填参数、 `[]`是可选参数
// program
//   .version(pkg.version)
//   .usage(`${chalk.green(`<must1> <must2> [option1] [option2]`)}`)
//   /*.action((must1,must2,option1,option2)=>{
//    // console.log('must1:', must1);
//    // console.log('must2:',must2);
//    // console.log('option1:',option1);
//    // console.log('option2:',option2);
//  })*/
//   .name(Object.keys(pkg.bin||{})?.[0] || 'create-react-app')
//
// // 下面 “Usage: test1command <must1> <must2> [option1] [option2]” 的 test1command 就是上面的.name()设置的
// //
// // PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js --help
// // Usage: test1command <must1> <must2> [option1] [option2]
// //
// // Options:
// //   -V, --version  output the version number
// // -h, --help     display help for command
//
//   .option(
//     //flags
//     '-d, --debug',
//     //description
//     '是否开启调试模式',
//     //defaultValue
//     false
//   )
//   .option('-e, --env <envName>', '获取环境变量名称')
//   //program.opts().env
//
//   .parse(process.argv)
//
// // console.log('program.debug:',program.debug)
// // 老版↑ 新版↓
// console.log('program.opts().debug:',program.opts().debug)
// // console.log('program.env:',program.env)
// // 老版↑ 新版↓
// console.log('program.opts().env:',program.opts().env)


//endregion



//region 一些其它的api

//打印帮助信息
// program.outputHelp()

//接受到的所有参数
// console.log(program.opts()); //{ debug: true, env: 'fwfw' }

//endregion



//region 3. command注册命令

//`<>`是必填参数、 `[]`是可选参数

// const command = program
//   .command('clone <source> [destination]'); //Returns: new command
// command
//   .description('clone a repository')
//   .option('-f, --force', 'force clone', false)
//   //如果传了一个不支持的opt, commander也会帮我们给出提示 "error: unknown option '-ew'"
//   .action((firstArg,secArg, cmdExtraOpts)=>{
//     console.log('do clone');
//     console.log('firstArg:',firstArg);
//     console.log('secArg:',secArg);
//     console.log('cmdExtraOpts:',cmdExtraOpts); //cmdExtraOpts: { force: true }
//   })
//
// program
//   .version(pkg.version)
//   .usage(`${chalk.green(`<must1> <must2> [option1] [option2]`)}`)
//   /*.action((must1,must2,option1,option2)=>{
//    // console.log('must1:', must1);
//    // console.log('must2:',must2);
//    // console.log('option1:',option1);
//    // console.log('option2:',option2);
//  })*/
//   .name(Object.keys(pkg.bin||{})?.[0] || 'create-react-app')
//   .option('-d, --debug', '是否开启调试模式', false)
//   .option('-e, --env <envName>', '获取环境变量名称')
//
//   .parse(process.argv)

// PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js clone aaa bbb --force
// do clone
// firstArg: aaa
// secArg: bbb
// cmdExtraOpts: { force: true }

//endregion



//region 4. addCommand注册子命令

// const command = program
//   .command('clone <source> [destination]'); //Returns: new command
// command
//   .description('clone a repository')
//   .option('-f, --force', 'force clone', false)
//   //如果传了一个不支持的opt, commander也会帮我们给出提示 "error: unknown option '-ew'"
//   .action((firstArg,secArg, cmdExtraOpts)=>{
//     console.log('do clone');
//     console.log('firstArg:',firstArg);
//     console.log('secArg:',secArg);
//     console.log('cmdExtraOpts:',cmdExtraOpts); //cmdExtraOpts: { force: true }
//   })
//
//
// //相较于↑这种添加命令的方式，下面这种方式可以添加子命令，即可以把命令分组
// const serviceCommand = new commander.Command('service');
// serviceCommand
//   .command('start [port]')
//   .description('start service at some port')
//   .action((port)=>{
//     console.log('do service start');
//     console.log('port:',port);
//   })
// serviceCommand
//   .command('stop')
//   .description('stop service')
//   .action(()=>{
//     console.log('do service stop');
//   })
//
// program.addCommand(serviceCommand)
//
// program
//   .version(pkg.version)
//   .usage(`${chalk.green(`<must1> <must2> [option1] [option2]`)}`)
//   /*.action((must1,must2,option1,option2)=>{
//    // console.log('must1:', must1);
//    // console.log('must2:',must2);
//    // console.log('option1:',option1);
//    // console.log('option2:',option2);
//  })*/
//   .name(Object.keys(pkg.bin||{})?.[0] || 'create-react-app')
//   .option('-d, --debug', '是否开启调试模式', false)
//   .option('-e, --env <envName>', '获取环境变量名称')
//
//   .parse(process.argv)


// PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js -h
// Usage: test1command <must1> <must2> [option1] [option2]
//
// Options:
//   -V, --version                           output the version number
// -d, --debug                             是否开启调试模式 (default: false)
// -e, --env <envName>                     获取环境变量名称
// -h, --help                              display help for command
//
//   Commands:
//     clone [options] <source> [destination]  clone a repository
// service
// help [command]                          display help for command

//   PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js service -h
// Usage: test1command service [options] [command]
//
// Options:
//   -h, --help      display help for command
//
//   Commands:
//     start [port]    start service at some port
// stop            stop service
// help [command]  display help for command

//endregion



//region 5. 高级命令： arguments --- 兜底命令

// const command = program
//   .command('clone <source> [destination]'); //Returns: new command
// command
//   .description('clone a repository')
//   .option('-f, --force', 'force clone', false)
//   //如果传了一个不支持的opt, commander也会帮我们给出提示 "error: unknown option '-ew'"
//   .action((firstArg,secArg, cmdExtraOpts)=>{
//     console.log('do clone');
//     console.log('firstArg:',firstArg);
//     console.log('secArg:',secArg);
//     console.log('cmdExtraOpts:',cmdExtraOpts); //cmdExtraOpts: { force: true }
//   })
//
//
// //相较于↑这种添加命令的方式，下面这种方式可以添加子命令，即可以把命令分组
// const serviceCommand = new commander.Command('service');
// serviceCommand
//   .command('start [port]')
//   .description('start service at some port')
//   .action((port)=>{
//     console.log('do service start');
//     console.log('port:',port);
//   })
// serviceCommand
//   .command('stop')
//   .description('stop service')
//   .action(()=>{
//     console.log('do service stop');
//   })
//
// program.addCommand(serviceCommand)
//
// program
//   .version(pkg.version)
//   .usage(`${chalk.green(`<must1> <must2> [option1] [option2]`)}`)
//   /*.action((must1,must2,option1,option2)=>{
//    // console.log('must1:', must1);
//    // console.log('must2:',must2);
//    // console.log('option1:',option1);
//    // console.log('option2:',option2);
//  })*/
//   .name(Object.keys(pkg.bin||{})?.[0] || 'create-react-app')
//   .option('-d, --debug', '是否开启调试模式', false)
//   .option('-e, --env <envName>', '获取环境变量名称')
//
//   //类似于 Yargs.demandCommand
//   .arguments('<cmd> [options]')
// // 因为↑ 使用了 <> , 故如果撒也不传控制台就会报错 （如果不设置.arguments, 那默认撒也不传的情况下会打印help信息）
// // PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js
// // error: missing required argument 'cmd'
//   .description('test command', {
//     cmd: 'command to run',
//     options: 'options for command'
//   })
//   .action(function (cmd, options) {
//     console.log('cmd:', cmd);
//     console.log('options:', options);
//   })
//   // .arguments('<must1> <must2> [option1] [option2]')
//   // .action((must1,must2,option1,option2)=>{
//   //   console.log(must1, must2, option1, option2);
//   // })
//
//   .parse(process.argv)

//endregion


//region 6. 高级命令： program.command 不设置action时 以及 command 系统配置选项

const command = program
  .command('clone <source> [destination]'); //Returns: new command
command
  .description('clone a repository')
  .option('-f, --force', 'force clone', false)
  //如果传了一个不支持的opt, commander也会帮我们给出提示 "error: unknown option '-ew'"
  .action((firstArg,secArg, cmdExtraOpts)=>{
    console.log('do clone');
    console.log('firstArg:',firstArg);
    console.log('secArg:',secArg);
    console.log('cmdExtraOpts:',cmdExtraOpts); //cmdExtraOpts: { force: true }
// node .\02.commander.js clone aaa bbb ccc -f
// preAction---
// do clone
// firstArg: aaa
// secArg: bbb
// cmdExtraOpts: { force: true }
// postAction---

// node .\02.commander.js clone a -f
// preAction---
// do clone
// firstArg: a
// secArg: undefined
// cmdExtraOpts: { force: true }
// postAction---
  })
  .hook('preAction', (cmd, actionCommand)=>{
  console.log('preAction---');
  })
  .hook('postAction', (cmd, actionCommand)=>{
    console.log('postAction---');
  })

//如果我们是program.command直接 点command 注册的命令，
//它的机制和在上面 program.command 返回的一个command里再.来设置是不一样的
//上面是你command()里接受的撒, 你生成的就是撒,
//比如你使用上面的注册方式 program.command('install <name>')
//那么命令行中你就可以输入 clixxx clone aaa , 然后他执行的时候找的也是我们这里的这个command的action
//但如果使用的我们↓的这种方式，你在命令行中需要这么使用：clixxx install aaa，它会去找 clixxx-install 这个命令的action来执行
//
// PS C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv> node .\02.commander.js install aa
// node:internal/modules/cjs/loader:1078
// throw err;
// ^
//
// Error: Cannot find module 'C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\14.process&child_process\01.argv\02.commander-install'
// at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15)
// at Module._load (node:internal/modules/cjs/loader:920:27)
// at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
// at node:internal/main/run_main_module:23:47 {
//   code: 'MODULE_NOT_FOUND',
//     requireStack: []
// }
//
// Node.js v18.15.0
//
//上面的例子会去找 02.commander-install 命令
program
  .command(
    'install [name]',
    'install package',
    {
      //修改命令的执行文件,
      //比如我们原本在命令行中输入的是 xxcli install xxx
      //我们这里executableFile设置为了 gg
      //那么实际执行的就是 gg xxx
      //即 会把 xxcli install -> gg
      // executableFile: 'gg',
      //↑ 方便多个脚手架之间串行使用

      // 默认情况下，撒命令也不传的话，会打印help信息 （设置了.argument兜底的话, 就会走argument）
      // 但你也可以把我们当前的这个命令设置为默认命令，通过↓这种方式
      // isDefault:true

      // 是否在help信息中隐藏这个命令
      // hidden: true
    }
  )
  .alias('i')



//相较于↑这种添加命令的方式，下面这种方式可以添加子命令，即可以把命令分组
const serviceCommand = new Command('service');
serviceCommand
  .command('start [port]')
  .description('start service at some port')
  .action((port)=>{
    console.log('do service start');
    console.log('port:',port);
  })
serviceCommand
  .command('stop')
  .description('stop service')
  .action(()=>{
    console.log('do service stop');
  })

program.addCommand(serviceCommand)

program
  .version(pkg.version)
  .usage(`${chalk.green(`<must1> <must2> [option1] [option2]`)}`)
  /*.action((must1,must2,option1,option2)=>{
   // console.log('must1:', must1);
   // console.log('must2:',must2);
   // console.log('option1:',option1);
   // console.log('option2:',option2);
 })*/
  .name(Object.keys(pkg.bin||{})?.[0] || 'create-react-app')
  .option('-d, --debug', '是否开启调试模式', false)
  .option('-e, --env <envName>', '获取环境变量名称')

  //类似于 Yargs.demandCommand
  .arguments('<cmd> [options]')
  .description('test command', {
    cmd: 'command to run',
    options: 'options for command'
  })
  .action(function (cmd, options) {
    console.log('cmd:', cmd);
    console.log('options:', options);
  })
  // .arguments('<must1> <must2> [option1] [option2]')
  // .action((must1,must2,option1,option2)=>{
  //   console.log(must1, must2, option1, option2);
  // })

  .parse(process.argv)

//endregion


//region 针对某个命令或者选项进行监听

//监听某个选项，比如下面就是监听 debug （--debug） 选项
program.on('option:debug', function() {
  console.log(program.opts());
  if (program.opts().debug) {
    log.verbose('debug', 'launch debug mode');
  }
});

//匹配任何未知命令
program.on('command:*', function(obj) {
  log.error('未知的命令：' + obj[0]);
});
//endregion

//相关项目
//C:\Users\fancier\code\js_workplace\tutorial\node\node_tutorial\docs\12.http\03static\02static-server\bin\www.js
